package org.zjx.core;

import com.sun.jna.platform.win32.WinDef;
import lombok.Data;
import org.zjx.command.ICommand;
import org.zjx.enums.GameStatus;
import org.zjx.enums.WindowState;
import java.awt.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * 屏幕窗口 - 支持引用计数通知（整改后版本）
 */
@Data
public class ScreenWindow implements IWindow, Runnable {
    private final String id;
    private final Rectangle bounds;
    private final BlockingQueue<ICommand> commandQueue;
    private final WindowSession parentSession;
    private volatile boolean running = false;
    private Thread executionThread;
    private final Object shutdownLock = new Object();
    private GameWindow boundWindow;

    public ScreenWindow(String id, Rectangle bounds, WindowSession parentSession) {
        if (id == null || id.trim().isEmpty()) {
            throw new IllegalArgumentException("Window id cannot be null or empty");
        }
        if (bounds == null) {
            throw new IllegalArgumentException("Bounds cannot be null");
        }
        if (parentSession == null) {
            throw new IllegalArgumentException("Parent session cannot be null");
        }

        this.id = id;
        this.bounds = bounds;
        this.parentSession = parentSession;
        this.commandQueue = new LinkedBlockingQueue<>();
        this.running = true;

        this.executionThread = new Thread(this, "ScreenWindow-Thread-" + id);
        this.executionThread.start();
        System.out.println("[ScreenWindow] " + id + " created and started");
    }

    public void setBoundWindow(GameWindow window) {
        this.boundWindow = window;
        System.out.println("[ScreenWindow] " + id + " bound to window: " +
                (window != null ? window.getId() : "null"));
    }

    @Override
    public void run() {
        System.out.println("[ScreenWindow] " + id + " execution thread started");

        while (running || !commandQueue.isEmpty()) {
            try {
                ICommand command = commandQueue.poll(100, TimeUnit.MILLISECONDS);
                if (command != null) {
                    executeCommand(command);
                }
            } catch (InterruptedException e) {
                synchronized (shutdownLock) {
                    if (!running) {
                        System.out.println("[ScreenWindow] " + id + " execution thread interrupted during shutdown");
                        break;
                    }
                }
                Thread.currentThread().interrupt();
                System.err.println("[ScreenWindow] " + id + " execution thread unexpectedly interrupted");
                break;
            } catch (Exception e) {
                System.err.println("[ScreenWindow] Error in " + id + " execution thread: " + e.getMessage());
            }
        }

        System.out.println("[ScreenWindow] " + id + " execution thread stopped");
    }

    private void executeCommand(ICommand command) {
        if (command == null) return;

        try {
            System.out.println("[ScreenWindow] " + id + " executing command: " + command.getCommandName());
            long startTime = System.currentTimeMillis();

            command.execute();

            long duration = System.currentTimeMillis() - startTime;
            System.out.println("[ScreenWindow] " + id + " completed command: " + command.getCommandName() + " in " + duration + "ms");

            // 通知Session命令执行完成（新增引用计数管理）
            if (parentSession != null) {
                parentSession.commandCompleted();
            }

        } catch (Exception e) {
            System.err.println("[ScreenWindow] Error executing command in " + id + ": " + e.getMessage());
            e.printStackTrace();

            // 异常时也要通知Session（新增引用计数管理）
            if (parentSession != null) {
                parentSession.commandCompleted();
            }
        }
    }

    @Override
    public boolean submitCommand(ICommand command) {
        if (command == null) {
            System.err.println("[ScreenWindow] Cannot submit null command to: " + id);
            return false;
        }

        if (!running) {
            System.err.println("[ScreenWindow] Cannot submit command to stopped window: " + id);
            return false;
        }

        if (boundWindow != null && command.getTargetWindow() != boundWindow) {
            System.err.println("[ScreenWindow] Command target window mismatch for: " + id);
            return false;
        }

        boolean success = commandQueue.offer(command);
        if (success) {
            System.out.println("[ScreenWindow] Command " + command.getCommandName() +
                    " submitted to " + id + " via Command system");
        }

        return success;
    }

    public void stop() {
        synchronized (shutdownLock) {
            if (!running) {
                return;
            }

            System.out.println("[ScreenWindow] Stopping: " + id);
            running = false;

            if (executionThread != null && executionThread.isAlive()) {
                executionThread.interrupt();
            }
        }

        try {
            if (executionThread != null) {
                executionThread.join(5000);
                if (executionThread.isAlive()) {
                    System.err.println("[ScreenWindow] " + id + " thread did not terminate gracefully");
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("[ScreenWindow] Interrupted while waiting for " + id + " to stop");
        }

        commandQueue.clear();
        System.out.println("[ScreenWindow] " + id + " stopped completely");
    }

    /**
     * 安全关闭窗口，执行剩余指令
     */
    public void shutdown() {
        System.out.println("[ScreenWindow] Gracefully shutting down: " + id);

        // 先停止接收新命令
        synchronized (shutdownLock) {
            running = false;
        }

        // 等待队列中的指令执行完成（带超时）
        long startTime = System.currentTimeMillis();
        long timeoutMs = 30000;

        while (!commandQueue.isEmpty() && (System.currentTimeMillis() - startTime) < timeoutMs) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }

        if (!commandQueue.isEmpty()) {
            System.err.println("[ScreenWindow] " + id + " timeout while waiting for commands to complete");
        }

        stop();
    }

    /**
     * 强制立即关闭（不清空队列）
     */
    public void forceShutdown() {
        synchronized (shutdownLock) {
            if (!running) {
                return;
            }

            System.out.println("[ScreenWindow] Force shutting down: " + id);
            running = false;
            commandQueue.clear(); // 清空队列

            if (executionThread != null && executionThread.isAlive()) {
                executionThread.interrupt();
            }
        }

        try {
            if (executionThread != null) {
                executionThread.join(2000);
                if (executionThread.isAlive()) {
                    System.err.println("[ScreenWindow] " + id + " thread did not terminate gracefully");
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("[ScreenWindow] Interrupted while waiting for " + id + " to stop");
        }

        System.out.println("[ScreenWindow] " + id + " force stopped completely");
    }

    // 添加获取队列大小的方法
    public int getQueueSize() {
        return commandQueue.size();
    }

    // 添加检查队列是否为空的方法
    public boolean isQueueEmpty() {
        return commandQueue.isEmpty();
    }

    // IWindow接口实现
    @Override
    public GameStatus getGameStatus() {
        return boundWindow != null ? boundWindow.getGameStatus() : null;
    }

    @Override
    public WindowState getWindowState() {
        return boundWindow != null ? boundWindow.getWindowState() : WindowState.UNKNOWN;
    }

    @Override
    public WinDef.HWND getHwnd() {
        return boundWindow != null ? boundWindow.getHwnd() : null;
    }

    @Override
    public Rectangle getBounds() {
        return bounds;
    }

    @Override
    public String getId() {
        return id;
    }
}